import cv2
import numpy as np
import time
import threading
from datetime import datetime
import tkinter as tk
from tkinter import ttk
import PIL.Image, PIL.ImageTk

class PendulumDetector:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("物理钟摆运动检测系统")
        
        # 窗口最大化
        self.root.state('zoomed')
        
        # 摄像头相关
        self.cap = None
        self.is_running = False
        self.frame = None
        
        # 检测参数
        self.target_color = np.array([68, 68, 97])  # BGR格式的目标颜色
        self.color_tolerance = 30  # 增加颜色容差
        self.center_line_x = 0
        
        # 取色器相关
        self.is_picking_color = False
        self.detection_point = None  # 检测点坐标
        
        # 计数和计时
        self.pass_count = 0
        self.start_time = None
        self.last_pass_time = None
        self.is_counting = False
        
        # 检测状态
        self.was_in_center = False
        self.currently_detected = False  # 当前是否检测到目标
        self.last_detection_time = 0  # 上次检测时间，用于防重复判定
        self.detection_cooldown = 0.02  # 检测冷却时间（秒）
        
        # 日志文件
        self.log_file = "pendulum_log.txt"
        self.init_log_file()
        
        self.setup_ui()
        self.start_camera()
        
    def setup_ui(self):
        # 主框架
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 左侧信息面板
        left_frame = ttk.Frame(main_frame, width=200)
        left_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10))
        left_frame.pack_propagate(False)
        
        ttk.Label(left_frame, text="统计信息", font=('Arial', 14, 'bold')).pack(pady=10)
        
        # 经过次数显示
        ttk.Label(left_frame, text="经过次数:", font=('Arial', 12)).pack(pady=5)
        self.count_label = ttk.Label(left_frame, text="0", font=('Arial', 24, 'bold'))
        self.count_label.pack(pady=5)
        
        # 计时显示（秒.小数点后两位）
        ttk.Label(left_frame, text="运行时间(秒):", font=('Arial', 12)).pack(pady=(20, 5))
        self.time_seconds_label = ttk.Label(left_frame, text="0.00", font=('Arial', 24, 'bold'))
        self.time_seconds_label.pack(pady=5)
        
        # 重置按钮
        ttk.Button(left_frame, text="重置计数", command=self.reset_count).pack(pady=10)
        
        # 检测状态显示
        ttk.Separator(left_frame, orient='horizontal').pack(fill='x', pady=10)
        ttk.Label(left_frame, text="检测状态", font=('Arial', 14, 'bold')).pack(pady=10)
        
        self.detection_status_label = ttk.Label(left_frame, text="未检测到", 
                                            font=('Arial', 12, 'bold'), foreground='red')
        self.detection_status_label.pack(pady=5)
        
        # 调试控制
        ttk.Separator(left_frame, orient='horizontal').pack(fill='x', pady=10)
        ttk.Label(left_frame, text="调试选项", font=('Arial', 14, 'bold')).pack(pady=10)
        
        self.show_debug = False
        self.debug_button = ttk.Button(left_frame, text="显示调试", command=self.toggle_debug)
        self.debug_button.pack(pady=5)
        
        # 取色器控制
        ttk.Separator(left_frame, orient='horizontal').pack(fill='x', pady=10)
        ttk.Label(left_frame, text="取色器", font=('Arial', 14, 'bold')).pack(pady=10)
        
        self.color_picker_button = ttk.Button(left_frame, text="开始取色", command=self.toggle_color_picker)
        self.color_picker_button.pack(pady=5)
        
        self.color_display = ttk.Label(left_frame, text="当前颜色: 未设置", font=('Arial', 10))
        self.color_display.pack(pady=5)
        
        self.detection_point_label = ttk.Label(left_frame, text="检测点: 摄像头中心", font=('Arial', 10))
        self.detection_point_label.pack(pady=5)
        
        # 测试检测按钮
        self.test_detection_button = ttk.Button(left_frame, text="测试当前检测", command=self.test_current_detection)
        self.test_detection_button.pack(pady=5)
        
        # 简单测试模式
        self.simple_test_button = ttk.Button(left_frame, text="简单测试", command=self.simple_color_test)
        self.simple_test_button.pack(pady=5)
        
        # 中间摄像头画面
        center_frame = ttk.Frame(main_frame)
        center_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        
        self.video_label = ttk.Label(center_frame)
        self.video_label.pack(fill=tk.BOTH, expand=True)
        
        # 绑定鼠标点击事件
        self.video_label.bind("<Button-1>", self.on_mouse_click)
        
        # 右侧计时器面板
        right_frame = ttk.Frame(main_frame, width=200)
        right_frame.pack(side=tk.RIGHT, fill=tk.Y, padx=(10, 0))
        right_frame.pack_propagate(False)
        
        ttk.Label(right_frame, text="计时器", font=('Arial', 14, 'bold')).pack(pady=10)
        
        # 计时显示
        ttk.Label(right_frame, text="运行时间:", font=('Arial', 12)).pack(pady=5)
        self.time_label = ttk.Label(right_frame, text="00:00:00", font=('Arial', 18, 'bold'))
        self.time_label.pack(pady=5)
        
        # 上次经过时间
        ttk.Label(right_frame, text="上次经过:", font=('Arial', 12)).pack(pady=(20, 5))
        self.last_pass_label = ttk.Label(right_frame, text="--:--:--", font=('Arial', 14))
        self.last_pass_label.pack(pady=5)
        
        # 控制按钮
        control_frame = ttk.Frame(right_frame)
        control_frame.pack(pady=20)
        
        self.start_button = ttk.Button(control_frame, text="开始检测", command=self.start_detection)
        self.start_button.pack(pady=5)
        
        self.stop_button = ttk.Button(control_frame, text="停止检测", command=self.stop_detection)
        self.stop_button.pack(pady=5)
        
        # 状态显示
        self.status_label = ttk.Label(right_frame, text="状态: 待机", font=('Arial', 10))
        self.status_label.pack(pady=10)
        
    def start_camera(self):
        try:
            # 尝试打开默认摄像头
            self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
            if not self.cap.isOpened():
                # 尝试其他摄像头索引
                for i in range(1, 5):
                    self.cap = cv2.VideoCapture(i, cv2.CAP_DSHOW)
                    if self.cap.isOpened():
                        break
                else:
                    raise Exception("无法打开任何摄像头")
            
            # 设置摄像头分辨率（如果支持）
            try:
                self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
                self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
                
                # 验证实际分辨率
                actual_width = self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)
                actual_height = self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
                print(f"摄像头分辨率: {int(actual_width)}x{int(actual_height)}")
                
            except Exception as e:
                print(f"设置分辨率失败，使用默认分辨率: {e}")
            
            # 设置缓冲区大小
            self.cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
            
            self.is_running = True
            self.update_frame()
            self.status_label.config(text="状态: 摄像头已连接")
            
        except Exception as e:
            error_msg = f"摄像头错误: {str(e)}"
            print(error_msg)
            self.status_label.config(text=error_msg)
            
            # 创建测试图像
            self.create_test_frame()
            
    def update_frame(self):
        if self.is_running and self.cap is not None:
            ret, frame = self.cap.read()
            if ret:
                self.frame = frame.copy()
                
                # 获取画面中心位置
                height, width = frame.shape[:2]
                self.center_line_x = width // 2
                
                # 绘制中心线
                cv2.line(frame, (self.center_line_x, 0), (self.center_line_x, height), 
                        (0, 255, 0), 2)
                
                # 绘制检测范围（左右100像素，从y=100开始避开顶部）
                left_bound = self.center_line_x - 100
                right_bound = self.center_line_x + 100
                cv2.rectangle(frame, (left_bound, 100), (right_bound, height), 
                            (0, 255, 0), 3)  # 绿色矩形框表示检测范围
                
                # 绘制顶部忽略区域分界线（红色实线）
                cv2.line(frame, (0, 100), (width, 100), (0, 0, 255), 2)
                cv2.putText(frame, "顶部100像素忽略区域", (10, 90), 
                           cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
                            
                # 绘制中心线（红色虚线，从y=100开始）
                for y in range(100, height, 20):
                    cv2.line(frame, (self.center_line_x, y), 
                            (self.center_line_x, min(y + 10, height)), 
                            (0, 0, 255), 1)
                
                # 始终显示掩码预览（右上角）
                mask_resized = cv2.resize(mask, (200, 150))
                mask_colored = cv2.cvtColor(mask_resized, cv2.COLOR_GRAY2BGR)
                frame[10:160, width-210:width-10] = mask_colored
                cv2.putText(frame, "检测掩码", (width-210, 180), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
                
                # 显示目标颜色（左上角）
                target_color_display = np.zeros((50, 50, 3), dtype=np.uint8)
                target_color_display[:, :] = self.target_color
                target_color_display_resized = cv2.resize(target_color_display, (50, 50))
                frame[10:60, 10:60] = target_color_display_resized
                cv2.putText(frame, "目标色", (10, 80), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
                
                # 绘制检测点标记（绿点）
                self.draw_detection_marker(frame)
                
                # 检测颜色
                if self.is_counting:
                    self.detect_color(frame)
                
                # 转换为RGB格式用于显示
                frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                image = PIL.Image.fromarray(frame_rgb)
                
                # 调整图像大小以适应窗口
                window_width = self.video_label.winfo_width()
                window_height = self.video_label.winfo_height()
                if window_width > 1 and window_height > 1:
                    image = image.resize((window_width, window_height), PIL.Image.LANCZOS)
                
                photo = PIL.ImageTk.PhotoImage(image)
                self.video_label.config(image=photo)
                self.video_label.image = photo
                
                # 更新计时器
                if self.is_counting and self.start_time:
                    elapsed = time.time() - self.start_time
                    self.time_label.config(text=self.format_time(elapsed))
                    self.time_seconds_label.config(text=f"{elapsed:.2f}")
            
            self.root.after(30, self.update_frame)
    
    def detect_color(self, frame):
        if frame is None:
            return
            
        try:
            # 使用取色器选择的颜色进行检测
            target_bgr = self.target_color.astype(np.uint8)
            
            # 创建颜色掩码，使用HSV颜色空间提高鲁棒性
            hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
            
            # 将BGR颜色转换为HSV
            target_bgr_3d = np.uint8([[target_bgr]])
            target_hsv = cv2.cvtColor(target_bgr_3d, cv2.COLOR_BGR2HSV)[0][0]
            
            # 大幅放宽检测条件
            hue_tolerance = 25  # 增加色相容差
            sat_tolerance = 80  # 增加饱和度容差
            val_tolerance = 80  # 增加明度容差
            
            lower_bound = np.array([
                max(0, target_hsv[0] - hue_tolerance),
                max(0, target_hsv[1] - sat_tolerance),
                max(0, target_hsv[2] - val_tolerance)
            ])
            upper_bound = np.array([
                min(180, target_hsv[0] + hue_tolerance),
                min(255, target_hsv[1] + sat_tolerance),
                min(255, target_hsv[2] + val_tolerance)
            ])
            
            # 创建HSV掩码
            mask = cv2.inRange(hsv_frame, lower_bound, upper_bound)
            
            # 形态学操作，去除噪声但保留更多细节
            kernel = np.ones((3,3), np.uint8)
            mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
            mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
            
            # 调试信息：显示掩码中的白色像素数量
            white_pixels = cv2.countNonZero(mask)
            if white_pixels > 0:
                print(f"HSV检测到 {white_pixels} 个匹配像素")
            
            # 查找颜色区域的轮廓
            contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            
            is_in_center = False
            self.currently_detected = False  # 重置检测状态
            
            # 调试：显示所有轮廓数量
            print(f"找到 {len(contours)} 个轮廓")
            
            # 寻找最大的轮廓作为主要检测目标
            max_area = 0
            best_contour = None
            
            for contour in contours:
                area = cv2.contourArea(contour)
                if area > 1:  # 极低阈值，几乎检测所有东西
                    if area > max_area:
                        max_area = area
                        best_contour = contour
            
            # 使用最大轮廓进行检测
            if best_contour is not None:
                area = max_area
                x, y, w, h = cv2.boundingRect(best_contour)
                center_x = x + w // 2
                center_y = y + h // 2
                
                # 忽略顶部100像素的检测（避免天花板干扰）
                if y < 100:
                    print(f"忽略顶部检测: y={y} < 100")
                    cv2.rectangle(frame, (x, y), (x + w, y + h), (128, 128, 128), 1)  # 灰色标记忽略区域
                else:
                    # 检查是否在中心线左右100像素范围内（使用新的100像素范围）
                    if abs(center_x - self.center_line_x) <= 100:
                        is_in_center = True
                        self.currently_detected = True  # 设置检测到状态
                        
                        # 绘制检测到的区域
                        cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 255), 2)
                        cv2.circle(frame, (center_x, center_y), 8, (0, 255, 0), -1)
                        
                        # 添加检测信息
                        cv2.putText(frame, f"Area: {int(area)}", (x, y-10), 
                                   cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
                        
                        print(f"检测到目标: 面积={int(area)}, 位置=({center_x}, {center_y})")
                    else:
                        # 即使不在中心，也绘制检测到的区域（蓝色）
                        cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 1)
            
            # 更新左侧检测状态显示
            if self.is_counting:  # 只有在检测模式下才更新状态
                if self.currently_detected:
                    self.detection_status_label.config(text="检测到目标", foreground='green')
                else:
                    self.detection_status_label.config(text="未检测到", foreground='red')
            
            # 检测经过事件（从非中心到中心，且满足冷却时间）
            current_time = time.time()
            time_since_last_detection = current_time - self.last_detection_time
            
            if is_in_center and not self.was_in_center and time_since_last_detection >= self.detection_cooldown:
                self.pass_count += 1
                self.count_label.config(text=str(self.pass_count))
                self.last_detection_time = current_time  # 更新上次检测时间
                
                # 第一次检测到时自动开始记录（无论是否手动启动）
                if self.start_time is None:
                    self.start_time = current_time
                    self.is_counting = True  # 确保计数状态为开启
                    self.status_label.config(text="状态: 自动计时中")
                    self.start_button.config(state='disabled')
                    self.stop_button.config(state='normal')
                
                elapsed_time = current_time - self.start_time
                self.last_pass_time = elapsed_time
                self.time_seconds_label.config(text=f"{elapsed_time:.2f}")
                self.time_label.config(text=self.format_time(elapsed_time))
                
                # 写入日志
                self.write_log(self.pass_count, elapsed_time)
                print(f"检测到经过! 计数: {self.pass_count}, 时间: {elapsed_time:.2f}秒")
            
            # 只在计数状态下更新时间显示（防止一直刷新）
            elif self.is_counting and self.start_time is not None:
                elapsed_time = current_time - self.start_time
                self.time_seconds_label.config(text=f"{elapsed_time:.2f}")
                self.time_label.config(text=self.format_time(elapsed_time))
            
            # 调试信息：显示检测时间间隔
            if time_since_last_detection < 1.0 and self.is_counting:
                print(f"检测间隔: {time_since_last_detection:.3f}秒")
                
        except Exception as e:
            print(f"检测错误: {e}")
            
        self.was_in_center = is_in_center
    
    def format_time(self, seconds):
        if seconds is None:
            return "--:--:--"
        hours = int(seconds // 3600)
        minutes = int((seconds % 3600) // 60)
        secs = int(seconds % 60)
        return f"{hours:02d}:{minutes:02d}:{secs:02d}"
    
    def init_log_file(self):
        """初始化日志文件，每次运行时清空"""
        try:
            with open(self.log_file, 'w', encoding='utf-8') as f:
                f.write("物理钟摆运动检测日志\n")
                f.write("=" * 50 + "\n")
                f.write(f"开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
                f.write("=" * 50 + "\n\n")
        except Exception as e:
            print(f"初始化日志文件失败: {e}")
    
    def write_log(self, count, elapsed_time):
        """写入日志记录"""
        try:
            with open(self.log_file, 'a', encoding='utf-8') as f:
                timestamp = datetime.now().strftime('%H:%M:%S.%f')[:-3]
                f.write(f"[{timestamp}] 第{count}次经过，用时: {elapsed_time:.2f}秒\n")
        except Exception as e:
            print(f"写入日志失败: {e}")
    
    def start_detection(self):
        self.is_counting = True
        self.start_time = time.time()
        self.status_label.config(text="状态: 检测中")
        self.start_button.config(state='disabled')
        self.stop_button.config(state='normal')
    
    def stop_detection(self):
        self.is_counting = False
        self.status_label.config(text="状态: 已停止")
        self.start_button.config(state='normal')
        self.stop_button.config(state='disabled')
        
        # 自动打开日志文件
        try:
            import os
            import subprocess
            if os.path.exists(self.log_file):
                # 使用默认文本编辑器打开日志文件
                os.startfile(self.log_file)
                print(f"已打开日志文件: {self.log_file}")
            else:
                print("日志文件不存在")
        except Exception as e:
            print(f"打开日志文件失败: {e}")
    
    def toggle_debug(self):
        """切换调试模式"""
        self.show_debug = not self.show_debug
        if self.show_debug:
            self.debug_button.config(text="隐藏调试")
        else:
            self.debug_button.config(text="显示调试")
    
    def test_current_detection(self):
        """测试当前检测效果"""
        if self.cap is not None and self.cap.isOpened():
            ret, frame = self.cap.read()
            if ret and hasattr(self, 'target_color'):
                self.detect_color(frame)
                print("测试检测完成，请查看视频画面和左侧状态")
    
    def simple_color_test(self):
        """简单颜色测试 - 使用红色作为测试颜色"""
        # 设置红色作为测试颜色 (BGR格式)
        self.target_color = np.array([0, 0, 255])  # 纯红色
        self.color_display.config(text="当前颜色: 红色(测试)")
        print("已设置为红色测试颜色，请将红色物体放在摄像头前测试检测功能")
        
        # 立即开始检测
        if not self.is_counting:
            self.start_detection()
            print("已开始检测，观察红色物体是否被检测到")
    
    def reset_count(self):
        self.pass_count = 0
        self.start_time = None
        self.last_pass_time = None
        self.auto_started = False
        self.count_label.config(text="0")
        self.time_label.config(text="00:00:00")
        self.last_pass_label.config(text="--:--:--")
        self.time_seconds_label.config(text="0.00")
        self.was_in_center = False
        
        # 重置取色器设置
        # self.detection_point = None
        # self.color_display.config(text="当前颜色: 未设置")
        # self.detection_point_label.config(text="检测点: 摄像头中心")
        self.currently_detected = False
        self.detection_status_label.config(text="未检测到", foreground='red')
        self.last_detection_time = 0  # 重置检测时间
        self.show_debug = False
        self.debug_button.config(text="显示调试")
        
        # 重新初始化日志文件
        self.init_log_file()
        
        # 重置状态显示
        self.status_label.config(text="状态: 待机")
        self.start_button.config(state='normal')
        self.stop_button.config(state='disabled')
    
    def run(self):
        self.root.protocol("WM_DELETE_WINDOW", self.on_closing)
        self.root.mainloop()
    
    def create_test_frame(self):
        """创建测试图像，用于没有摄像头的情况"""
        self.is_running = True
        self.update_test_frame()
    
    def update_test_frame(self):
        """更新测试图像"""
        if not self.is_running:
            return
            
        # 创建测试图像
        height, width = 480, 640
        test_frame = np.zeros((height, width, 3), dtype=np.uint8)
        
        # 绘制背景
        test_frame[:] = (50, 50, 50)
        
        # 绘制中心线
        center_x = width // 2
        cv2.line(test_frame, (center_x, 0), (center_x, height), (0, 255, 0), 2)
        
        # 绘制检测范围（左右50像素）
        left_bound = center_x - 50
        right_bound = center_x + 50
        cv2.rectangle(test_frame, (left_bound, 0), (right_bound, height), 
        (255, 255, 0), 1)  # 黄色矩形框表示检测范围
        
        # 绘制检测点标记（绿点）
        cv2.circle(test_frame, (center_x, height // 2), 5, (0, 255, 0), -1)
        cv2.circle(test_frame, (center_x, height // 2), 7, (0, 255, 0), 2)
        
        # 绘制模拟钟摆（使用取色器选择的颜色）
        pendulum_x = center_x + int(100 * np.sin(time.time() * 2))
        # 确保模拟钟摆y坐标在100以下，避免与顶部忽略区域重叠
        pendulum_y = max(height // 2, 120)  # 至少120像素，避开顶部100像素忽略区域
        target_color = self.target_color.astype(np.uint8)
        cv2.circle(test_frame, (pendulum_x, pendulum_y), 20, 
        (int(target_color[0]), int(target_color[1]), int(target_color[2])), -1)
        
        # 添加文字说明
        cv2.putText(test_frame, "测试模式 - 无摄像头", (10, 30), 
                   cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
        cv2.putText(test_frame, "按开始检测测试功能", (10, 60), 
                   cv2.FONT_HERSHEY_SIMPLEX, 0.5, (200, 200, 200), 1)
        
        # 转换为RGB格式
        frame_rgb = cv2.cvtColor(test_frame, cv2.COLOR_BGR2RGB)
        image = PIL.Image.fromarray(frame_rgb)
        
        # 调整图像大小
        window_width = self.video_label.winfo_width()
        window_height = self.video_label.winfo_height()
        if window_width > 1 and window_height > 1:
            image = image.resize((window_width, window_height), PIL.Image.LANCZOS)
        
        photo = PIL.ImageTk.PhotoImage(image)
        self.video_label.config(image=photo)
        self.video_label.image = photo
        
        # 模拟检测
        if self.is_counting:
            # 模拟钟摆经过中心（左右50像素范围内）
            if abs(pendulum_x - center_x) <= 50 and not self.was_in_center:
                self.pass_count += 1
                self.count_label.config(text=str(self.pass_count))
                
                current_time = time.time()
                if self.start_time is None:
                    self.start_time = current_time
                    self.status_label.config(text="状态: 自动计时中")
                
                elapsed_time = current_time - self.start_time
                self.last_pass_time = elapsed_time
                self.time_seconds_label.config(text=f"{elapsed_time:.2f}")
                self.time_label.config(text=self.format_time(elapsed_time))
            
            self.was_in_center = abs(pendulum_x - center_x) <= 50
            
            # 绘制检测区域（绿色矩形），从y=100开始避开顶部忽略区域
            cv2.rectangle(frame, (center_x - 50, 100), (center_x + 50, height), (0, 255, 0), 3)
            
            # 绘制中心线（红色虚线），从y=100开始
            for y in range(100, height, 20):
                cv2.line(frame, (center_x, y), 
                       (center_x, min(y + 10, height)), 
                       (0, 0, 255), 1)
        
        # 更新计时器
        if self.start_time:
            elapsed = time.time() - self.start_time
            self.time_label.config(text=self.format_time(elapsed))
            self.time_seconds_label.config(text=f"{elapsed:.2f}")
        
        self.root.after(100, self.update_test_frame)
    
    def update_frame(self):
        if self.is_running and self.cap is not None:
            ret, frame = self.cap.read()
            if ret:
                self.frame = frame.copy()
                
                # 获取画面中心位置
                height, width = frame.shape[:2]
                self.center_line_x = width // 2
                
                # 绘制中心线
                cv2.line(frame, (self.center_line_x, 0), (self.center_line_x, height), 
                        (0, 255, 0), 2)
                
                # 检测颜色
                if self.is_counting:
                    self.detect_color(frame)
                
                # 转换为RGB格式用于显示
                frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                image = PIL.Image.fromarray(frame_rgb)
                
                # 调整图像大小以适应窗口
                window_width = self.video_label.winfo_width()
                window_height = self.video_label.winfo_height()
                if window_width > 1 and window_height > 1:
                    image = image.resize((window_width, window_height), PIL.Image.LANCZOS)
                
                photo = PIL.ImageTk.PhotoImage(image)
                self.video_label.config(image=photo)
                self.video_label.image = photo
                
                # 更新计时器
                if self.is_counting and self.start_time:
                    elapsed = time.time() - self.start_time
                    self.time_label.config(text=self.format_time(elapsed))
            else:
                # 如果读取失败，切换到测试模式
                self.create_test_frame()
                return
            
            self.root.after(30, self.update_frame)
    
    def on_closing(self):
        self.is_running = False
        if self.cap is not None:
            self.cap.release()
        self.root.destroy()
    
    def toggle_color_picker(self):
        """切换取色器状态"""
        self.is_picking_color = not self.is_picking_color
        if self.is_picking_color:
            self.color_picker_button.config(text="取消取色")
            self.status_label.config(text="状态: 取色模式中 - 点击画面选择颜色")
        else:
            self.color_picker_button.config(text="开始取色")
            self.status_label.config(text="状态: 待机")
    
    def on_mouse_click(self, event):
        """处理鼠标点击事件，用于取色"""
        if not self.is_picking_color or self.frame is None:
            return
            
        try:
            # 获取点击位置
            label_width = self.video_label.winfo_width()
            label_height = self.video_label.winfo_height()
            
            if label_width <= 1 or label_height <= 1:
                return
                
            # 计算在原始图像中的位置
            frame_height, frame_width = self.frame.shape[:2]
            scale_x = frame_width / label_width
            scale_y = frame_height / label_height
            
            x = int(event.x * scale_x)
            y = int(event.y * scale_y)
            
            # 确保坐标在图像范围内
            x = max(0, min(x, frame_width - 1))
            y = max(0, min(y, frame_height - 1))
            
            # 获取该点的颜色
            color = self.frame[y, x]
            self.target_color = color.astype(np.float64)
            
            # 更新显示
            color_str = f"RGB({int(color[2])}, {int(color[1])}, {int(color[0])})"
            self.color_display.config(text=f"当前颜色: {color_str}")
            
            # 设置检测点为点击位置
            self.detection_point = (x, y)
            self.detection_point_label.config(text=f"检测点: ({x}, {y})")
            
            # 自动关闭取色器
            self.is_picking_color = False
            self.color_picker_button.config(text="开始取色")
            self.status_label.config(text="状态: 颜色已设置")
            
            print(f"已选择颜色: {color_str} 在位置 ({x}, {y})")
            
        except Exception as e:
            print(f"取色失败: {e}")
            self.status_label.config(text="状态: 取色失败")
    
    def draw_detection_marker(self, frame):
        """绘制检测点标记"""
        if self.detection_point is not None:
            # 在检测点位置绘制绿点
            cv2.circle(frame, self.detection_point, 5, (0, 255, 0), -1)
            cv2.circle(frame, self.detection_point, 7, (0, 255, 0), 2)
        else:
            # 如果没有设置检测点，使用摄像头中心
            height, width = frame.shape[:2]
            center = (width // 2, height // 2)
            cv2.circle(frame, center, 5, (0, 255, 0), -1)
            cv2.circle(frame, center, 7, (0, 255, 0), 2)

if __name__ == "__main__":
    detector = PendulumDetector()
    detector.run()